require 'opengl'
require 'lib/gosu'
require 'lib/chipmunk'
require 'include/GLBackground.rb'
require 'include/Shot.rb'
require 'include/Player.rb'
require 'include/Baddy.rb'
require 'include/Star.rb'
require 'include/Numeric.rb'
require 'include/Lost.rb'

include Gl, Glu

SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 768
SUBSTEPS = 6
$SHOT_LIMIT = 50
$LEVEL = 1
$SHOT_ANGLE = 0
$GAME_STATE = 1
$STATE = 1
$CAN_PLAY = true
@new_game = true

module ZOrder
  Stars, Shot, Player, Baddy, Explosion, UI = *0..3
end

class GameWindow < Gosu::Window
  
  def playSong(sound)
    @sng = Gosu::Song::new(self, "media/"+sound+".ogg")
    @sng.play
  end
  
  def playSound(sound)
    @snd = Gosu::Sample::new(self, "media/"+sound+".ogg")
    @snd.play
  end

  def collisions
    # keep track of shapes to remove on collision
    @remove_star_shapes = []
    @remove_enemy_shapes = []
    @remove_shot_shapes = []
    
    $space.add_collision_func(:hero, :enemy) do |@hero_shape, @badguy_shape|
      # random gulp sound
      @sound = 1 + rand(4)
      case @sound
      when 1
        playSound("gulp#{@sound}")
      when 2
        playSound("gulp#{@sound}")
      when 3
        playSound("gulp#{@sound}")
      when 4
        playSound("gulp#{@sound}")
      end
      #playSound("Explosion")
      @remove_enemy_shapes << @badguy_shape
      #@remove_hero_shapes << @hero_shape
      @player.hp -= 20
      $LEVEL += 1
      playSound("Explosion")
    end
    
    $space.add_collision_func(:shot, :enemy) do |@shot_shape, @badguy_shape|
      # random gulp sound
      @sound = 1 + rand(4)
      case @sound
      when 1
        playSound("gulp#{@sound}")
      when 2
        playSound("gulp#{@sound}")
      when 3
        playSound("gulp#{@sound}")
      when 4
        playSound("gulp#{@sound}")
      end
      @remove_shot_shapes << @shot_shape
      @player.score += 5
      @baddies.last.hp -= @player.weapon_power
      #if hp lower than 0 blow up
      if (@baddies.last.hp <= 0)
        #@baddies.last.explode
        @remove_enemy_shapes << @badguy_shape
        $LEVEL += 1
        @player.score += 50
        playSound("Explosion")
      end
    end
    
    $space.add_collision_func(:badguy_shot, :hero) do |@shot_shape, @hero_shape|
      @remove_shot_shapes << @shot_shape
      @player.score -= 5
      @player.hp -= 1
      #if hp lower than 0 blow up
      if (@player.hp <= 0)
        playSound("Explosion")
        @player.score -= 50
      end
      
    end
    
    $space.add_collision_func(:hero, :star) do |@hero_shape, @star_shape|
      @player.score += 10
      if @player.speed < 2.0
        @player.speed += 0.05
      end
      @player.hp += 25
      @player.weapon_power += 0.1
      $SHOT_LIMIT += 50
      playSound("beep")
      @remove_star_shapes << @star_shape
    end
    
    $space.add_collision_func(:enemy, :star, &nil)
  end
  
  def initialize
    super(SCREEN_WIDTH, SCREEN_HEIGHT, false)
    
    #build the basics of the screen
    self.caption = "Hamburger Hunt"

    #draw canyon back ground
    @gl_background = GLBackground.new(self)
    @font = Gosu::Font.new(self, Gosu::default_font_name, 20)
    
    #@intro = Gosu::Song::new(self, "media/credits.ogg")
    #@intro.play
    @sng = Gosu::Song::new(self, "media/bgLev1.ogg")
    @sng.play
    
    @dt = (1.0/60.0)
    
    # Create our Space and set damping
    $space = CP::Space.new
    $space.damping = 0.7
    
    @player = Player.new(self)
    @player.warp(CP::Vec2.new( SCREEN_WIDTH/2, (SCREEN_HEIGHT/2)+150 ))
    @baddies = []
    @stars = []
    @shots = []
    @badguy_shots = []
    collisions
  end
  
  def clean_up
    if (@remove_star_shapes.size > 0)
      @remove_star_shapes.each do |shape|
        @stars.delete_if { |star| star.star_shape == shape }
        $space.remove_body(shape.body)
        $space.remove_shape(shape)
      end
      @remove_star_shapes.clear
    end
      
    if (@remove_enemy_shapes.size > 0)
      @remove_enemy_shapes.each do |shape|
        @baddies.delete_if { |baddy| baddy.badguy_shape == shape }
        $space.remove_body(shape.body)
        $space.remove_shape(shape)
      end
      @remove_enemy_shapes.clear
    end
      
    if (@remove_shot_shapes.size > 0)
      @remove_shot_shapes.each do |shape|
        @shots.delete_if { |shot| shot.shot_shape == shape }
        $space.remove_body(shape.body)
        $space.remove_shape(shape)
      end
      @remove_shot_shapes.clear
    end
  end
  
  def update
    # Step the physics environment SUBSTEPS times each update
    SUBSTEPS.times do
      clean_up
      # Perform the step over @dt period of time
      $space.step(@dt)
    end
    
    if $CAN_PLAY == true
      movement_logic
      shot_logic
    end
    @baddies.each { |baddy| baddy.validate_position }
    @player.validate_position
    @gl_background.scroll
  end
  
  def draw
      
    gl do
      glClearColor(0.0, 0.2, 0.5, 1.0)
      glClearDepth(0)
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
      @gl_background.exec_gl
    end
    
    drawEverything
    displayHUD
  end
  
  def movement_logic
    # force reset so that thrust does not compound
    @player.hero_shape.body.reset_forces
    @baddies.each { |baddy| baddy.badguy_shape.body.reset_forces }
    @shots.each { |shot| shot.shot_shape.body.reset_forces }
    
    # Check keyboard / gamepad
    if (button_down? Gosu::Button::KbLeft) or (button_down? Gosu::Button::GpLeft)
      @player.turn_left
    end
    if (button_down? Gosu::Button::KbRight) or (button_down? Gosu::Button::GpRight)
      @player.turn_right
    end
    
    if (button_down? Gosu::Button::KbUp) or (button_down? Gosu::Button::GpUp)
      if (button_down? Gosu::Button::GpButton8)
        @player.boost
      else
        @player.accelerate
      end
    elsif (button_down? Gosu::Button::KbDown) or (button_down? Gosu::Button::GpDown)
      @player.reverse
    end
  end
  
  def shot_logic
    # delete bullets out of screen
    @shots.delete_if { |shot| ( shot.y <= 1 ||
                                shot.y >= SCREEN_HEIGHT ||
                                shot.x <= 1 ||
                                shot.x >= SCREEN_WIDTH ) }
    if $SHOT_LIMIT > 0 and @shot_ok == true
      if (button_down? Gosu::Button::KbSpace) or (button_down? Gosu::Button::GpButton3)
        
        # angle shot left
        if (button_down? Gosu::Button::KbLeftShift) or (button_down? Gosu::Button::GpButton7)
          
          $SHOT_ANGLE -= 15
          shoot
          
        # angle shot right
        elsif (button_down? Gosu::Button::KbRightShift) or (button_down? Gosu::Button::GpButton9)
          $SHOT_ANGLE += 15
          shoot
          
        # no angle change
        else
          shoot
        end
        
      end
    end
    
  end

  def shoot
    @shot = Shot.new( self, @player, $SHOT_ANGLE )
    @shots.push( @shot )
    
    # random shot sound
    @sound = 1 + rand(5)
    case @sound
    when 1
      playSound("shot#{@sound}")
    when 2
      playSound("shot#{@sound}")
    when 3
      playSound("shot#{@sound}")
    when 4
      playSound("shot#{@sound}")
    when 5
      playSound("shot#{@sound}")
    end
    $SHOT_LIMIT -= 1
  end
  
  def badguy_shoot
    @badguy_shot = Shot.new( self, @baddies.last, $SHOT_ANGLE )
    #~ @badguy_shot.shot_shape.collision_type = :badguy_shot
    @baddy_shots.push( @badguy_shot )
  end

  def drawEverything
    @player.draw
    @player.hero_shape.body.a = ( 3*Math::PI/2.0 )
    
    if ( @baddies.length < $LEVEL )
      @baddies.push(Baddy.new(self))
      @baddies.last.warp(CP::Vec2.new( (rand*SCREEN_WIDTH), -50 ))
    end
    
    # Each update we see if we need to add more Stars
    if ( rand(2000)<15 and @stars.size<3 )
      @star = Star.new( self )
      @stars.push( @star )
    end
    
    # delete any star that is out of the screen
    @stars.delete_if { |star| ( star.y <= 1 ||
                                star.y >= SCREEN_HEIGHT ||
                                star.x <= 1 ||
                                star.x >= SCREEN_WIDTH ) }
    
    @baddies.each { |baddy| baddy.draw }
    @baddies.each { |baddy| baddy.movement }
    @stars.each { |star| star.draw }
    @shots.each { |shot| shot.draw }
  end

  def displayHUD
    if @new_game == true
      @larc = Gosu::Image.new(self, "media/larc.bmp", false)
      @title = Gosu::Image.new(self, "media/title.png", false)
      @press_enter = Gosu::Image.new(self, "media/pressEnter.png", false)
      
      case $STATE
      when 1
        @larc.draw( 0, 0, ZOrder::Title )
      when 2
        @title.draw( 0, 0, ZOrder::Title )
      when 3
        @press_enter.draw( 0, 0, ZOrder::Title )
      end
      
      @intro.stop
      @new_game = false
    end
    
    if @player.hp < 0
        $CAN_PLAY = false
      @font.draw("FAIL: EATEN", 10, 70, 0, 10.0, 10.0, 0xffffff00)
      @font.draw("press fire to continue", 10, 10, 0, 1.0, 1.0, 0xffffff00)
      if (button_down? Gosu::Button::GpButton3) or (button_down? Gosu::Button::KbSpace)
        playSong("bgLev1")
        @player.hp = 100
        $SHOT_LIMIT = 50
        $LEVEL = 1
        $SHOT_ANGLE = 0
        $CAN_PLAY = true
      end
    else
      @font.draw("Speed: #{@player.speed}", 10, 150, 0, 1.0, 1.0, 0xffffff00)
      @font.draw("Score: #{@player.score}", 10, 130, 0, 1.0, 1.0, 0xffffff00)
      @font.draw("Ammo: #{$SHOT_LIMIT}", 10, 70, 0, 1.0, 1.0, 0xffffff00)
      @font.draw("Weapon Power: #{@player.weapon_power}", 10, 110, 0, 1.0, 1.0, 0xffffff00)
      @font.draw("BITES LEFT: #{@player.hp}", 10, 90, 0, 1.0, 1.0, 0xffffff00)
      @font.draw("You need to kill all the mouths to go to the next level.", 10, 10, 0, 1.0, 1.0, 0xffffff00)
      @font.draw("L and R changes the angle of your shots", 10, 30, 0, 1.0, 1.0, 0xffffff00)
      @font.draw("Grab stars to heal yourself, speed up, and get ammo", 10, 50, 0, 1.0, 1.0, 0xffffff00)
    end
    
  end

  def button_down(id)
    if id == Gosu::Button::KbEscape
      close
    end
  end
  
  def button_up(id)
    if id == Gosu::Button::KbSpace or Gosu::Button::GpButton3
      @shot_ok = true
    else
      @shot_ok = false
    end
    
  end
  
end

#case $GAME_STATE
#when 1
  game_window = GameWindow.new
  game_window.show
#when 3
#  win_window = WinWindow.new
#  win_window.show
#when 4
#  lost_window = LostWindow.new
#  lost_window.show
#end